#include "factory.h"
#include "ui_factory.h"
#include "msgbox.h"
#include "systempreset.h"
#include "motorcalibdialog.h"
#include "userlogger.h"
#include "ettadatastruct.h"
#include "blldataflow.h"
#include "screenmanager.h"
#include "powermanager.h"
#include "buzzer.h"
#include "viewlogsdialog.h"
#include "udiskexport.h"
#include "loading.h"

Factory::Factory(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Factory)
{
    ui->setupUi(this);
    initWidget();
}

Factory::~Factory()
{
    delete ui;
}

void Factory::save(const QString &path)
{// 导出数据

}

void Factory::retranslateUiSlot()
{
    ui->retranslateUi(this);
}

void Factory::initWidget()
{
    initParams();

    connect(BllDataFlow::getInstance(), &BllDataFlow::retranslateUiSignal, this, &Factory::retranslateUiSlot);

    connect(ui->btnDebug, &QPushButton::toggled, this, &Factory::onChangePage);
    connect(ui->btnMotor, &QPushButton::toggled, this, &Factory::onChangePage);
    connect(ui->btnProduct, &QPushButton::toggled, this, &Factory::onChangePage);
    connect(ui->btnVoltage, &QPushButton::toggled, this, &Factory::onChangePage);
    connect(ui->btnFlowRate, &QPushButton::toggled, this, &Factory::onChangePage);
    connect(ui->btnOscilloscope, &QPushButton::toggled, this, &Factory::onChangePage);

    connect(ui->btnSaveOscilloscopeParam, &QPushButton::clicked, this, &Factory::onSaveOscilloscopeParam);
    connect(ui->btnSaveVoltageCalibParam, &QPushButton::clicked, this, &Factory::onSaveVoltageCalibParam);
    connect(ui->btnSaveFlowRateCalibParam, &QPushButton::clicked, this, &Factory::onSaveFlowRateCalibParam);
    connect(ui->btnSaveProductConfig, &QPushButton::clicked, this, &Factory::onSaveProductConfig);
    connect(ui->btnMotorCalib, &QPushButton::clicked, this, &Factory::onMotorCalibClicked);

    connect(ui->chkDisableSystemDesktop, &QCheckBox::stateChanged, this, &Factory::onDebugRebootStateChanged);
    connect(ui->chkOpenAutoFillBarCode, &QCheckBox::stateChanged, this, &Factory::onDebugCheckboxChanged);
    connect(ui->chkShowRememberPassWord, &QCheckBox::stateChanged, this, &Factory::onDebugCheckboxChanged);
    connect(ui->chkAllowLoginWhenBootFail, &QCheckBox::stateChanged, this, &Factory::onDebugCheckboxChanged);

    connect(ui->lineFinishExpOffsetTimes, &CustomNumEdit::lostFocus, this, &Factory::onDebugInputLostFocus);
    connect(ui->lineSelfTestMaxTimes, &CustomNumEdit::lostFocus, this, &Factory::onDebugInputLostFocus);
    connect(ui->lineStopExpDlayTimes, &CustomNumEdit::lostFocus, this, &Factory::onDebugInputLostFocus);
    connect(ui->lineDiskWarningSize, &CustomNumEdit::lostFocus, this, &Factory::onDebugInputLostFocus);
    connect(ui->lineDiskMinSize, &CustomNumEdit::lostFocus, this, &Factory::onDebugInputLostFocus);

    connect(ui->lineBuzzerAudioVolume, &CustomNumEdit::lostFocus, this, &Factory::onDebugVolumeChanging);
    connect(ui->hsliderBuzzerAudioVolume, &QSlider::sliderMoved, this, &Factory::onDebugVolumeChanging);
    connect(ui->hsliderBuzzerAudioVolume, &QSlider::sliderReleased, this, &Factory::onDebugVolumeChanged);

    connect(ui->btnReboot, &QPushButton::clicked, this, &Factory::onDebugButtonClicked);
    connect(ui->btnViewLog, &QPushButton::clicked, this, &Factory::onDebugButtonClicked);
    connect(ui->btnExportData, &QPushButton::clicked, this, &Factory::onDebugButtonClicked);

    ui->btnReboot->hide();
}

void Factory::initParams()
{
    ui->lineVoltageProbeRate->init(1, 1000, 200);
    ui->lineVoltageZeroPos->init(-600, 600, 0.00, 2);
    ui->lineVoltageCalibCoef->init(0.01, 100, 1.00, 2);
    ui->lineFlowRateCalibCoef->init(0.01, 100, 1.00, 2);

    ui->lineFinishExpOffsetTimes->init(0, 1000, 0);
    ui->lineSelfTestMaxTimes->init(0, 1000, 0);
    ui->lineStopExpDlayTimes->init(0, 1000, 0);
    ui->lineDiskWarningSize->init(1000, 1000000, 1024);
    ui->lineDiskMinSize->init(100, 1000, 100);
    ui->lineBuzzerAudioVolume->init(0, 100, 30);
    ui->hsliderBuzzerAudioVolume->setRange(0, 100);

    ui->lineVoltageProbeRate->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::VoltageProbeRate));
    ui->lineVoltageZeroPos->setValue(SystemPreset::instance()->getDoubleData(EnumPresetItem::VoltageZeroPos));
    ui->lineVoltageCalibCoef->setValue(SystemPreset::instance()->getDoubleData(EnumPresetItem::VoltageCalibCoef));
    ui->lineFlowRateCalibCoef->setValue(SystemPreset::instance()->getDoubleData(EnumPresetItem::FlowRateCalibCoef));
    ui->lineSerialNumber->setText(SystemPreset::instance()->getStringData(EnumPresetItem::SerialNumber));

    ui->chkDisableSystemDesktop->setChecked(SystemPreset::instance()->getBoolData(EnumPresetItem::DisableSystemDesktop));
    ui->chkOpenAutoFillBarCode->setChecked(SystemPreset::instance()->getBoolData(EnumPresetItem::OpenAutoFillBarCode));
    ui->chkShowRememberPassWord->setChecked(SystemPreset::instance()->getBoolData(EnumPresetItem::ShowRememberPassWord));
    ui->chkAllowLoginWhenBootFail->setChecked(SystemPreset::instance()->getBoolData(EnumPresetItem::AllowLoginWhenBootFail));

    ui->lineFinishExpOffsetTimes->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::FinishExpOffsetTimes));
    ui->lineSelfTestMaxTimes->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::SelfTestMaxTimes));
    ui->lineStopExpDlayTimes->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::StopExpDlayTimes));
    ui->lineDiskWarningSize->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::DiskWarningSize));
    ui->lineDiskMinSize->setValue(SystemPreset::instance()->getIntData(EnumPresetItem::DiskMinSize));

    m_volume = SystemPreset::instance()->getIntData(EnumPresetItem::BuzzerAudioVolume);
    ui->lineBuzzerAudioVolume->setValue(m_volume);
    ui->hsliderBuzzerAudioVolume->setValue(m_volume);
}

void Factory::onChangePage(bool checked)
{
    static const QMap<QObject *, FactoryConfigIndex> mapper = {
        {ui->btnDebug, DEBUG},
        {ui->btnMotor, MOTOR},
        {ui->btnProduct, PRODUCT},
        {ui->btnVoltage, VOLTAGE},
        {ui->btnFlowRate, FLOWRATE},
        {ui->btnOscilloscope, OSCILLOSCOPE},
    };

    if (checked && mapper.contains(QObject::sender()))
    {// 每次切换页面，刷新当前的参数
        initParams();
        changeFactoryConfigPageIndexSlot(mapper[QObject::sender()]);
    }
}

struct FactoryParam {QLabel *label; QWidget *edit; int item;};

static void saveParam(const QList<FactoryParam> &params, bool showMessagebox = true)
{
    QString message;
    foreach (const FactoryParam &param, params)
    {
        QString oldValue, newValue;
        if (param.edit->inherits("CustomNumEdit"))
        {
            CustomNumEdit *input = qobject_cast<CustomNumEdit *>(param.edit);
            newValue = input->text();
            oldValue = SystemPreset::instance()->getStringData(param.item);
        }
        else if (param.edit->inherits("QLineEdit"))
        {
            QLineEdit *input = qobject_cast<QLineEdit *>(param.edit);
            newValue = input->text();
            oldValue = SystemPreset::instance()->getStringData(param.item);
        }
        else if (param.edit->inherits("QCheckBox"))
        {
            QCheckBox *input = qobject_cast<QCheckBox *>(param.edit);
            newValue = QString::number(input->isChecked());
            oldValue = SystemPreset::instance()->getStringData(param.item);
        }
        else
        {
            Q_ASSERT(false);
            continue;
        }

        if (oldValue != newValue)
        {
            SystemPreset::instance()->setData(param.item, newValue);
            message += QString("%1%2 -> %3;").arg(param.label->text()).arg(oldValue).arg(newValue);
        }
    }

    if (message.length() > 0)
    {
        UserLogger::log(message);
        if (showMessagebox)
        {
            MsgBox::information(0, QObject::tr("Factory"), QObject::tr("Save Successful"));
        }
    }
}

void Factory::onSaveOscilloscopeParam()
{
    static const QList<FactoryParam> params = {
        {ui->lblVoltageProbeRate, ui->lineVoltageProbeRate, EnumPresetItem::VoltageProbeRate},
        {ui->lblVoltageZeroPos, ui->lineVoltageZeroPos, EnumPresetItem::VoltageZeroPos},
    };

    saveParam(params);
}

void Factory::onSaveVoltageCalibParam()
{
    static const QList<FactoryParam> params = {
        {ui->lblVoltageCalibCoef, ui->lineVoltageCalibCoef, EnumPresetItem::VoltageCalibCoef},
    };

    saveParam(params);
}

void Factory::onSaveFlowRateCalibParam()
{
    static const QList<FactoryParam> params = {
        {ui->lblVoltageCalibCoef, ui->lineFlowRateCalibCoef, EnumPresetItem::FlowRateCalibCoef},
    };

    saveParam(params);
}

void Factory::onSaveProductConfig()
{
    static const QList<FactoryParam> params = {
        {ui->lblSerialNumber, ui->lineSerialNumber, EnumPresetItem::SerialNumber},
    };

    saveParam(params);
    BllDataFlow::getInstance()->updateLocalInfo();
}

void Factory::onMotorCalibClicked()
{
    MotorCalibDialog().show(false);
}

void Factory::onDebugInputLostFocus()
{
    static const QList<FactoryParam> params = {
        {ui->lblFinishExpOffsetTimes, ui->lineFinishExpOffsetTimes, EnumPresetItem::FinishExpOffsetTimes},
        {ui->lblSelfTestMaxTimes, ui->lineSelfTestMaxTimes, EnumPresetItem::SelfTestMaxTimes},
        {ui->lblStopExpDlayTimes, ui->lineStopExpDlayTimes, EnumPresetItem::StopExpDlayTimes},
        {ui->lblDiskWarningSize, ui->lineDiskWarningSize, EnumPresetItem::DiskWarningSize},
        {ui->lblDiskMinSize, ui->lineDiskMinSize, EnumPresetItem::DiskMinSize},
    };

    saveParam(params, false);
}

void Factory::onDebugCheckboxChanged()
{
    static const QList<FactoryParam> params = {
        {ui->lblOpenAutoFillBarCode, ui->chkOpenAutoFillBarCode, EnumPresetItem::OpenAutoFillBarCode},
        {ui->lblShowRememberPassWord, ui->chkShowRememberPassWord, EnumPresetItem::ShowRememberPassWord},
        {ui->lblAllowLoginWhenBootFail, ui->chkAllowLoginWhenBootFail, EnumPresetItem::AllowLoginWhenBootFail},
    };

    saveParam(params, false);
}

void Factory::onDebugVolumeChanging()
{
    Buzzer::instance()->stop();
    if (sender() == ui->hsliderBuzzerAudioVolume)
    {// 滑动条滚动
        ui->lineBuzzerAudioVolume->setValue(ui->hsliderBuzzerAudioVolume->value());
    }
    else if (sender() == ui->lineBuzzerAudioVolume)
    {// 输入框失去焦点
        ui->hsliderBuzzerAudioVolume->setValue(ui->lineBuzzerAudioVolume->value());
        onDebugVolumeChanged();
    }
}

void Factory::onDebugVolumeChanged()
{
    static const QList<FactoryParam> params = {
        {ui->lblBuzzerAudioVolume, ui->lineBuzzerAudioVolume, EnumPresetItem::BuzzerAudioVolume},
    };

    if (m_volume != ui->hsliderBuzzerAudioVolume->value())
    {// 保存参数，播放声音
        m_volume = ui->hsliderBuzzerAudioVolume->value();
        ui->lineBuzzerAudioVolume->setValue(m_volume);
        saveParam(params, false);
        Buzzer::instance()->setVolume(m_volume);
        Buzzer::instance()->start();
        QTimer::singleShot(3000, this, []
        {// 3s后停止播放
            Buzzer::instance()->stop();
        });
    }
}

void Factory::onDebugRebootStateChanged()
{
    static const QList<FactoryParam> params = {
        {ui->lblDisableSystemDesktop, ui->chkDisableSystemDesktop, EnumPresetItem::DisableSystemDesktop},
    };

    if (ui->chkDisableSystemDesktop->isChecked())
    {
        ScreenManager::blockSysDesktop();
        ScreenManager::blockHibernate();
    }
    else
    {
        ScreenManager::startSysDesktop();
    }

    saveParam(params, false);
    ui->btnReboot->setHidden(!ui->btnReboot->isHidden());
}

void Factory::onDebugButtonClicked()
{
    if (sender() == ui->btnReboot)
    {// 重启
        PowerManager::restart();
    }
    else if (sender() == ui->btnViewLog)
    {// 查看日志
        ViewLogsDialog().show(LogDir);
    }
    else if (sender() == ui->btnExportData)
    {// 导出数据
        //Loading::showLoading(QColor(0,0,0,200), false, tr("exporting..."));
        //UserLogger::log(tr("Export All Experiment data"));
        //exportMgr->exports(ReportType::FACTORY_DATA, this);
    }
}

void Factory::changeFactoryConfigPageIndexSlot(int index)
{
    if (index != -1)
    {
        ui->stackedWidget->setCurrentIndex(index);
        ui->stackedWidget->setVisible(true);
    }
    else
    {
        ui->stackedWidget->setVisible(false);
    }
}
